/**
 * 
 */
package design_pattern.immutable;

import java.io.Serializable;

/**
 * 不可变模式
 * 
 * @author linzq
 * 
 */
public final class Complex extends Number implements Serializable, Cloneable, Comparable {

  static final public Complex i = new Complex(0.0, 1.0);

  /** 实数 */
  private double re;

  /** 虚数 */
  private double im;

  public Complex(double re, double im) {
    this.re = re;
    this.im = im;
  }

  public Complex(Complex z) {
    this.re = z.re;
    this.im = z.im;
  }

  public Complex(double re) {
    this.re = re;
    this.im = 0.0;
  }

  public boolean equals(Complex z) {
    return (this.re == z.re && this.im == z.im);
  }

  public double real() {
    return this.re;
  }

  public double image() {
    return this.im;
  }

  public static double real(Complex z) {
    return z.re;
  }

  public static double image(Complex z) {
    return z.im;
  }

  /**
   * 返回复数的相反数
   * 
   * @param z
   * @return
   */
  public static Complex negate(Complex z) {
    return new Complex(-z.re, -z.im);
  }

  /**
   * 返回复数的共扼复数
   * 
   * @param z
   * @return
   */
  public static Complex conjugate(Complex z) {
    return new Complex(z.re, -z.im);
  }

  /**
   * 返回复数的和
   * 
   * @param z
   * @return
   */
  public static Complex add(Complex x, Complex z) {
    return new Complex(x.re + z.re, x.im + z.im);
  }

  /**
   * 返回复数的和
   * 
   * @param z
   * @return
   */
  public static Complex add(double x, Complex z) {
    return new Complex(x + z.re, z.im);
  }

  /**
   * 返回复数的差
   * 
   * @param z
   * @return
   */
  public static Complex substract(Complex x, Complex z) {
    return new Complex(x.re - z.re, x.im - z.im);
  }

  /**
   * 返回数的差
   * 
   * @param z
   * @return
   */
  public static Complex substract(Complex x, double z) {
    return new Complex(x.re - z, x.im);
  }

  /**
   * 返回数的差
   * 
   * @param z
   * @return
   */
  public static Complex substract(double z, Complex x) {
    return new Complex(z - x.re, x.im);
  }

  public static Complex multiply(Complex x, Complex y) {
    return new Complex(x.re * y.re - x.im * y.im, x.re * y.im - x.im * y.re);
  }

  public static Complex multiply(Complex x, double y) {
    return new Complex(x.re * y, x.im * y);
  }

  public static Complex multiplyImage(Complex x, double y) {
    return new Complex(-x.im * y, x.im * y);
  }

  public static Complex multiplyImage(double y, Complex x) {
    return new Complex(-x.im * y, x.im * y);
  }

  public static Complex divide(Complex x, Complex y) {
    double a = x.re;
    double b = x.im;
    double c = y.re;
    double d = y.im;
    double scale = Math.max(Math.abs(c), Math.abs(d));
    double den = c * c + d * d;
    return new Complex((a * c + b * d) / den, (b * c - a * d) / den);
  }

  public static Complex divide(Complex x, double y) {
    return new Complex(x.re / y, x.im / y);
  }

  public static Complex divide(double x, Complex y) {
    double den = 0.0, t = 0.0;
    Complex z = null;
    if (Math.abs(y.re) > Math.abs(y.im)) {
      t = y.im / y.re;
      den = y.re + y.im * t;
      z = new Complex(x / den, -x * t / den);
    } else {
      t = y.re / y.im;
      den = y.im + y.re * t;
      z = new Complex(x * t / den, -x / den);
    }
    return z;
  }

  public static double abs(Complex x) {
    return x.re * x.re - x.im * -x.im;
  }

  public static double argument(Complex x) {
    return Math.atan2(x.im, x.re);
  }

  @Override
  public int intValue() {
    return 0;
  }

  @Override
  public long longValue() {
    return 0;
  }

  @Override
  public float floatValue() {
    return 0;
  }

  @Override
  public double doubleValue() {
    return 0;
  }

  @Override
  public int compareTo(Object o) {
    return 0;
  }

  @Override
  public String toString() {
    return "Complex [re=" + re + ", im=" + im + "]";
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    long temp;
    temp = Double.doubleToLongBits(im);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(re);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Complex other = (Complex) obj;
    if (Double.doubleToLongBits(im) != Double.doubleToLongBits(other.im))
      return false;
    if (Double.doubleToLongBits(re) != Double.doubleToLongBits(other.re))
      return false;
    return true;
  }



}
